#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include  <unistd.h>
#include  <sys/types.h>		  /* basic system data types */
#include  <sys/socket.h>	  /* basic socket definitions */
#include  <netinet/in.h>	  /* sockaddr_in{} and other Internet defns */
#include  <arpa/inet.h>		  /* inet(3) functions */

#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

#define MAXLINE 1024

#ifdef DEBUG
#define	dbg(x...) printf(x)
#else
#define	dbg(x...)
#endif

//typedef struct sockaddr  SA;
void handle(int connfd);
static int fpga_fd=-1;

int fpga_init(char * devname)
{
	fpga_fd = open(devname, O_RDWR);
	if (fpga_fd < 0) {
		return -1;
	}
	dbg("%s: succeed\n",__func__);
	return 0;
}

int	fpga_term(void)
{
	close(fpga_fd);
}

int	 main(int argc, char **argv)
{
	int		listenfd, connfd;
	int	 	serverPort = 8888;
	int 	listenq = 1024;
	pid_t	childpid;
	char 	buf[MAXLINE];
	socklen_t socklen;
	int		ret;

	struct sockaddr_in cliaddr, servaddr;
	socklen = sizeof(cliaddr);

	ret = fpga_init("/dev/fpga");
	if(ret < 0)
	{
		perror("open device fpga");
		return 0;
	}

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(serverPort);

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0) {
		perror("socket error");
		return -1;
	}
	if (bind(listenfd, (struct sockaddr *) &servaddr, socklen) < 0) {
		perror("bind error");
		return -1;
	}
	if (listen(listenfd, listenq) < 0) {
		perror("listen error");	   
		return -1;
	}
	printf("echo server startup,listen on port:%d\n", serverPort);
	for ( ; ; )	 {
		connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &socklen);
		if (connfd < 0) {
			perror("accept error");
			continue;
		}

		sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
		printf(buf,"");
#if 1
		handle(connfd);	  /* process the request */
#else
		childpid = fork();
		if (childpid == 0) { /* child process */
			close(listenfd);	/* close listening socket */
			handle(connfd);	  /* process the request */
			exit (0);
		} else if (childpid > 0)  {
			close(connfd);			/* parent closes connected socket */
		} else {
			perror("fork error");
		}
#endif
	}
}
void thread_fpga_mon(int connfd)
{
	size_t	bytes;
	char	buf[2];
	while(1)
	{
		bytes = read(fpga_fd, buf, 2);
		if(bytes > 0)
		{
			printf("read bytes: 0x%x 0x%x\n", (unsigned int)buf[0], (unsigned int)buf[1]);
			write(connfd, buf, bytes); //write maybe fail,here don't process failed error
//			printf("connfd = 0x%x\n", connfd);
		}
		else
			usleep(1000);
		
	}
}

void thread_fpga_create(int connfd)
{
    pthread_t thread_id = 0;
    pthread_attr_t  attr;

    if(thread_id)
    {
        pthread_cancel(thread_id);
    }
    pthread_attr_init(&attr);
	
    if (pthread_create(&thread_id, &attr, (void*)&thread_fpga_mon, connfd))
    {
        printf("ERROR: can't create read_thread thread!\n");
    }
    else {
        printf("thread_fpga_mon started\n");
        pthread_detach(thread_id);
    }
}

void print_data(unsigned char *buf, int len);
void handle(int connfd)
{
	size_t n;
	char	buf[MAXLINE];
	
	thread_fpga_create(connfd);

	for(;;) {
		n = read(connfd, buf, MAXLINE);
		if (n < 0) {
			if(errno != EINTR) {
				perror("read error");
				break;
			}
		}
#if 0
		if (n == 0) {
			//connfd is closed by client
			close(connfd);
			printf("client exit\n");
			break;
		}
		//client exit
		if (strncmp("exit", buf, 4) == 0) {
			close(connfd);
			printf("client exit\n");
			break;
		}
#endif
		//write(connfd, buf, n); //write maybe fail,here don't process failed error
	//	print_data(buf, n);
		if(n > 0)
			write(fpga_fd, buf, n); //write maybe fail,here don't process failed error
	} 
}

void print_data(unsigned char *buf, int len)
{
	int i;
	for (i=0; i<len; i++){
		if(i%16 == 0)printf("\n");
		printf("%02x ", buf[i]);
	}
} 
